package com.platform.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer;
import com.alibaba.fastjson.serializer.ValueFilter;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;

/**
 * JSON对象工具类
 *
 * @author lipengjun
 * @email 939961241@qq.com
 * @date 2017年11月16日 下午10:43:36
 */
public final class JsonUtil {

  private JsonUtil() {
  }

  /***
   * 值过滤器
   */
  private static ValueFilter filter = new ValueFilter() {
    @Override
    public Object process(Object obj, String s, Object v) {
      if (v == null) {
        return "";
      }
      return v;
    }
  };
  private static SerializerFeature[] feature = {
      //解决FastJson循环引用的问题
      SerializerFeature.DisableCircularReferenceDetect,
      //输出值为null的字段
      SerializerFeature.WriteMapNullValue
  };
  private static SerializeConfig mapping = new SerializeConfig();

  static {
    mapping.put(Date.class, new SimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));
    mapping.put(Timestamp.class, new SimpleDateFormatSerializer("yyyy-MM-dd HH:mm:ss"));//数据库的一个时间类型
  }

  /**
   * 将对象转换成JSON字符串 --固定时间格式"yyyy-MM-dd HH:mm:ss"
   *
   * @param BO/VO,map,数组,list 对象
   * @return JSON字符串
   * @说明：对bean中有Date类型的数据可以成功转换成yyyy-MM-dd HH:mm:ss格式的时间类型,例如："barDate":yyyy-MM-dd HH:mm:ss
   */
  public static String getJsonByObj(Object bean) {
    return getJsonByObj(bean, mapping);
  }

  /**
   * 将对象转换成JSON字符串 --特定时间格式--所有Key为小写
   *
   * @param BO/VO,map,数组,list 对象
   * @return JSON字符串
   * @dateType 时间格式转换后的字符串格式，例如yyyy-MM-dd HH:mm:ss
   * @说明：对bean中有Date类型的数据可以成功转换成yyyy-MM-dd HH:mm:ss格式的时间类型,例如："barDate":yyyy-MM-dd HH:mm:ss
   */
  public static String getJsonByObj(Object bean, String dateType) {
    SerializeConfig zdymapping = new SerializeConfig();
    zdymapping.put(Date.class, new SimpleDateFormatSerializer(dateType));
    return getJsonByObj(bean, zdymapping);
  }

  /**
   * 将对象转换成JSON字符串 ---效率高一些--不处理key 也不处理循环引用的问题--也不处理时间格式
   *
   * @param BO/VO,map,数组,list 对象
   * @return JSON字符串
   * @说明：对bean中有Date类型的数据可以成功转换成long格式的时间类型,例如："barDate":1458268099098
   */
  public static String getJsonDefaultByObj(Object bean) {
    return JSON.toJSONString(bean);
  }

  /**
   * 将JSON数据转换为ListBean集合
   *
   * @param json JSON数组数据
   * @param calzz 待转换的Bean类型 --LinkedCaseInsensitiveMap
   */
  public static <T> List<T> getListBean(String json, Class<T> calzz) {
    return JSON.parseArray(json, calzz);
  }

  /**
   * 将JSON数据转换为List集合
   *
   * @param json JSON数组数据
   * @param calzz 待转换的Bean类型 --LinkedCaseInsensitiveMap
   */
  @SuppressWarnings({"rawtypes", "unchecked"})
  public static List getList(String json, Class calzz) {
    return getListBean(json, calzz);
  }

  /**
   * 将JSON数据转换为 Java Bea n对象
   *
   * @param json JSON字符串
   * @param calzz 待转换的Bean类型--LinkedCaseInsensitiveMap
   */
  public static <T> T getObjet(String json, Class<T> calzz) {
    return JSON.parseObject(json, calzz);
  }

  /***
   * 通用封装--获取json字符串
   * @param bean 对象
   * @param mappingx 时间类型计划等
   * @return
   */
  private static String getJsonByObj(Object bean, SerializeConfig mappingx) {
    String json = JSON.toJSONString(bean, mappingx, filter, feature);
    json = stringToJson(json);
    return json; //所有Key为小写
  }

  /**
   * 当文本中含有如下特殊字符时，此方法可以成功处理，让其在前台被正确解析，注意：此法不能处理单引号
   */
  public static String stringToJson(String s) {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < s.length(); i++) {
      char c = s.charAt(i);
      switch (c) {
                /*case '\"':
                    sb.append("\\\"");
					break;*/
        case '\\':   //如果不处理单引号，可以释放此段代码，若结合下面的方法处理单引号就必须注释掉该段代码
          sb.append("\\\\");
          break;
        case '/':
          sb.append("\\/");
          break;
        case '\b':      //退格
          sb.append("\\b");
          break;
        case '\f':      //走纸换页
          sb.append("\\f");
          break;
        case '\n':
          sb.append("\\n"); //换行
          break;
        case '\r':      //回车
          sb.append("\\r");
          break;
        case '\t':      //横向跳格
          sb.append("\\t");
          break;
        default:
          sb.append(c);
      }
    }
    return sb.toString();
  }


}
